level: any
What is Eddie?
Eddie is a new code editor written in Liberty BASIC, for Liberty BASIC. Eddie can be customized and extended to meet the needs of the individual programmer. The newest version is available here: Eddie!
Setting the Font Size
Eddie adds a feature to the Options Menu for this version. It allows the user to set the height of the font. The new options menu looks like this:
Menu #1, "&Options", "&Syntax Color On/Off",[syntaxColor],"&Line Numbers On/Off",[lineNumbers],|,_
"Set &Default Color", [doDefaultColor],"Set &Background Color", [doBackgroundColor],|,_
"Set &Keyword Color", [doKeywordColor],"Set &Comment Color", [doCommentColor],"Set &Quote Color",_
[doQuoteColor],"Set &Operator Color", [doOperatorColor], |, "&Font Size", [changeFont]
A simple call to CodeAChrome changes the font size. The value for the "nFont" argument sets the height of the font. There is no way to change the font face. Since CodeAChrome is intended for code editing, the Courier New monospaced font is used by default.
calldll #r, "SetFontSize",_
nFont as long,_ 'desired height of font
re as void
Eddie stores the size of the font in the variable FontSize$, which is a string variable, so the VAL() function is used to convert the value into a number for use in the API call. We prompt the user for a font size, and if the user selects a size smaller than 8, we set the size to 8. If he selects a size greater than 24, we set the size to 24. (This could also be done using MIN() and MAX() -- why not try converting it yourself?)
[changeFont]
nFont = val(FontSize$)
prompt "Size for font?";nFont
if nFont<8 then nFont = 8
if nFont>24 then nFont = 24
FontSize$ = str$(nFont)
call SetFontSize FontSize$
wait
Eddie calls the Sub to SetFontSize, which looks like this. The sub accepts a string variable and converts it to a numeric value for the API call.
Sub SetFontSize fSize$
nFont = val(fSize$)
calldll #r, "SetFontSize", nFont as long, re as void
calldll #r, "DoSetFocus", re as void
end sub
Changing the Ini File to API Version
This issue contains an article on API ini files. Please read that article to understand the changes in Eddie's ini file routines. Eddie will call on these two wrapper routines to write to and read from the ini file that saves user preferences.
Sub WriteIniFile lpAppName$, lpKeyName$, lpString$, lpFileName$
CallDLL #kernel32, "WritePrivateProfileStringA", _
lpAppName$ As ptr, _ 'section name
lpKeyName$ As ptr, _ 'key name
lpString$ As ptr, _ 'key value
lpFileName$ As ptr, _ 'ini filename
result As boolean 'nonzero = success
end sub
Function GetIniFile$(lpAppName$, lpKeyName$,lpDefault$,lpFileName$)
nSize=100
lpReturnedString$=Space$(nSize)+Chr$(0)
CallDLL #kernel32, "GetPrivateProfileStringA", _
lpAppName$ As ptr, _'section name
lpKeyName$ As ptr, _'key name
lpDefault$ As ptr, _'default string returned if there is no entry
lpReturnedString$ As ptr, _ 'destination buffer
nSize As long, _ 'size of destination buffer
lpFileName$ As ptr, _ 'ini filename
result As ulong 'number of characters copied to buffer
GetIniFile$=Left$(lpReturnedString$,result)
end function
The new routines that call on these API functions are below. The routines are more streamlined, since the API ini file allows us to set a default value if the key has no set value. We've also added to the ini file to save and retrieve the coordinates and size of the window when the user last ran Eddie.
[readIniFile]
LibertyExe$ = GetIniFile$("Eddie", "LibertyExe","none","eddie12.ini")
Freeform$ = GetIniFile$("Eddie", "Freeform","none","eddie12.ini")
Runtime$ = GetIniFile$("Eddie", "Runtime","none","eddie12.ini")
Help$ = GetIniFile$("Eddie", "Help","none","eddie12.ini")
TextColor$ = GetIniFile$("Eddie", "TextColor",TextColor$,"eddie12.ini")
BackColor$ = GetIniFile$("Eddie", "BackColor",BackColor$,"eddie12.ini")
KeywordColor$ = GetIniFile$("Eddie", "KeywordColor",KeywordColor$,"eddie12.ini")
QuoteColor$ = GetIniFile$("Eddie", "QuoteColor",QuoteColor$,"eddie12.ini")
CommentColor$ = GetIniFile$("Eddie", "CommentColor",CommentColor$,"eddie12.ini")
OperatorColor$ = GetIniFile$("Eddie", "OperatorColor",OperatorColor$,"eddie12.ini")
FontSize$ = GetIniFile$("Eddie", "FontSize",FontSize$,"eddie12.ini")
'window X,Y,WIDTH,HEIGHT at user's last values
ULX = VAL(GetIniFile$("Eddie", "ULX","10","eddie12.ini"))
ULY = VAL(GetIniFile$("Eddie", "ULY","10","eddie12.ini"))
WIDTH = VAL(GetIniFile$("Eddie", "WIDTH","400","eddie12.ini"))
HEIGHT = VAL(GetIniFile$("Eddie", "HEIGHT","300","eddie12.ini"))
if LibertyExe$ = "none" then
notice "To use Eddie successfully, you must set the path to Liberty.exe, Freeform, the runtime engine and the helpfile."
gosub [GetLibertyPath]
gosub [GetFreeformPath]
gosub [GetRuntimePath]
gosub [GetHelpPath]
end if
RETURN
[writeIniFile]
call WriteIniFile "Eddie", "LibertyExe", LibertyExe$,"eddie12.ini"
call WriteIniFile "Eddie", "Freeform", Freeform$,"eddie12.ini"
call WriteIniFile "Eddie", "Runtime", Runtime$,"eddie12.ini"
call WriteIniFile "Eddie", "Help", Help$,"eddie12.ini"
call WriteIniFile "Eddie", "TextColor", TextColor$,"eddie12.ini"
call WriteIniFile "Eddie", "BackColor", BackColor$,"eddie12.ini"
call WriteIniFile "Eddie", "KeywordColor", KeywordColor$,"eddie12.ini"
call WriteIniFile "Eddie", "QuoteColor", QuoteColor$,"eddie12.ini"
call WriteIniFile "Eddie", "CommentColor", CommentColor$,"eddie12.ini"
call WriteIniFile "Eddie", "OperatorColor", OperatorColor$,"eddie12.ini"
call WriteIniFile "Eddie", "FontSize", FontSize$,"eddie12.ini"
RETURN
Checking for a Minimized Window
We're adding a new feature to Eddie this month. We'll save the size and location of Eddie when the program ends, so that we can automatically open Eddie at those coordinates next time. Before checking for the coordinates, we need to make sure that the window hasn't been minimized to the task bar. It's not a good idea to start a program in the minimized mode. The code to check for a minimized window is explained in the article on API ini files in this issue.
Eddie's code to check for a minimized window is contained in the "quit" routine and it is as follows:
calldll #user32, "IsIconic",_
hMain as ulong,_ 'handle of window
result as boolean 'returns true if window is minimized
Retrieving Window Coorinates
In the "quit" routine, if the window is not minimized, we want to retrieve the window coordinates. This API function to GetWindowRect is explained in the article on API ini files in this issue. Here is Eddie's code to retrieve those coordinates and write them to the ini file.
[quit]
calldll #user32, "IsIconic",_
hMain as ulong,_ 'handle of window
result as boolean 'returns true if window is minimized
if not(result) then
struct Rect, x1 As Long, y1 As Long, x2 As Long, y2 As Long
CallDLL #user32, "GetWindowRect",hMain as uLong, Rect As struct, result As Long
ulx = Rect.x1.struct : uly = Rect.y1.struct
width = Rect.x2.struct - ulx
height = Rect.y2.struct - uly
'write location and size of window to ini file
call WriteIniFile "Eddie", "ULX", str$(ulx), "eddie12.ini"
call WriteIniFile "Eddie", "ULY", str$(uly), "eddie12.ini"
call WriteIniFile "Eddie", "WIDTH", str$(width), "eddie12.ini"
call WriteIniFile "Eddie", "HEIGHT", str$(height), "eddie12.ini"
end if
gosub [writeIniFile]
calldll #r, "DestroyCodeAChrome", ret as void
close #r : close #1 : END
Opening the Window at the User's Last Position
The API ini file allows us to set default values for the keys, so we can set defaults for UpperLeftX, UpperLeftY, WindowWidth and WindowHeight. If Eddie is being run for the first time, those defaults will be used. If the user has run Eddie before, the window will open at the last used coordinates and dimensions.
Before opening the window, we invoke a subroutine to read the ini file, like this:
gosub [readIniFile]
While reading the ini file, the UpperLeftX, UpperLeftY, WindowWidth and WindowHeight are set. Here's that part of the code:
'window X,Y,WIDTH,HEIGHT at user's last values
ULX = VAL(GetIniFile$("Eddie", "ULX","10","eddie12.ini"))
ULY = VAL(GetIniFile$("Eddie", "ULY","10","eddie12.ini"))
WIDTH = VAL(GetIniFile$("Eddie", "WIDTH","400","eddie12.ini"))
HEIGHT = VAL(GetIniFile$("Eddie", "HEIGHT","300","eddie12.ini"))
After reading the ini file and opening the window, we use those values to set the location and size of the window. Since we use the MoveWindow API call to invoke the resizehandler after opening the window, we'll use those values in the call:
'activate resizehandler
calldll #user32, "MoveWindow",_
hMain as ulong, _ 'window handle
ULX as long,_ 'x location of window
ULY as long,_ 'y location of window
WIDTH as long,_ 'desired width of window
HEIGHT as long,_ 'desired height of window
1 as boolean, ret as long